Вложенные элементы.
(оба браузера)

К сожалению, я не могу похвастаться авторством на идею этого замечательного примера. Идея принадлежит Дэну Стайнману (Dan Steinman). У него же взяты и картинки. Сама же программа была основательно переработана. Например, у Дэна, солнце было неподвижным и т.д.

В чем здесь суть? Дело в том, что солнце вращается по элиптической орбите вокруг некоторого центра. Замля, в свою очередь, вращается вокруг солнца, также по элиптической орбите. Наконец, Луна вращается вокруг Земли, опять же, по элиптической орбите. И все это вращается одновременно! Траектория Земли, довольно замысловата, а уж о траектории Луны и говорить нечего!

Как же удается справиться с таким сложным движением? Это было бы действительно трудно, если бы не идея использования объектов. Смотрите внимательно, собака зарыта именно здесь. Поняв это, Вы поймете все остальное. Итак:

  1. вся система в целом, как один элемент движется по элиптической орбите. При этом используется прстоая программа анимцаии, которая, просто двигает элемент. Ее абсолютно не интересует, что происходит внутри элемента. Для данной программы элемент - это нечто целое и неделимое;
  2. внутри этого эелемента (всей системы в целом) находится неподвижное солнце (именно неподвижное! движется сам эемент, а Солнце внутри него неподвижно!). Вокруг Солнца вращается еще один дочерний элемент - система Земля-Луна. Ее следует рассматривать как один целостный элемент. Этот элемент движется (внутри родительского элемента) по обыкновенному эллипсу. Значит, для его движения, тоже достаточно простой программы вращения по эллиптической траектории. Более того, можно использовать ту же самую программу, которая вращает всю систему;
  3. внутри системы Земля-Луна, находится неподвижный элемент - Земля и, движущийся по эллипсу, элемент - Луна. Опять, с точки зрения системы Земля-Луна, Земля неподвижна, а Луна вращается по эллипсу. Для вращения Луны, опять достаточно простой программы (той же самой, что и раньше).

Повторю по другому. Система в целом просто вращается по эллипсу. Если мы влезем внутрь этой системы (и будем двигаться по эллипсу вместе с ней), то мы обнаружим, что у нее два дочерних элемента - неподвижное солнце и система Земля-Луна. Последняя, внутри своего родителя, тоже просто вращается по эллипсу. Влезем внутрь системы Земля-Луна (двигаемся вместе с ней) и увидим, что внутри у нее имеется неподвижная Земля и, вращающаяся по обыкновенному эллипсу Луна.

Таким образом мы не связываемся со сложными траекториями. Нам удалось разложить сложное движения на три простых вращения по эллиптической траектории. Все эти три вращения может выполнять одна-единственная несложная программа. Что, кстати, в данном примере и делается.

Если Вам понятно вышеизложенное, то все остальное - дело техники, причем не такой уж и сложной тезники.

Система движущихся тел задается следующими тэгами:

<SPAN ID="allSpan" STYLE="position:absolute;left:0;top:80;width:336;height:316;">
  <SPAN ID="sunSpan" STYLE="position:absolute;left:131;top:90;width:71;">
    <IMG SRC="../images/sun.gif" WIDTH=71 HEIGHT=71 BORDER=0>
  </SPAN>
  <SPAN ID="earthMoonSpan" STYLE="position:absolute;left:232;top:72;width:100;height:100;">
    <SPAN ID="earthSpan" STYLE="position:absolute;z-index:2;left:34;top:34;width:32;height:32;">
      <IMG SRC="../images/earth.gif" WIDTH=32 HEIGHT=32 BORDER=0>
    </SPAN>
    <SPAN ID="moonSpan" STYLE="position:absolute;left:80;top:40;width:20;height:20;">
      <IMG SRC="../images/moon.gif" WIDTH=20 HEIGHT=20 BORDER=0>
    </SPAN>
  </SPAN>
</SPAN>

Здесь, "система в целом" - allSpan имеет двух потомков - Солнце (sunSpan) и систему Земля-Луна (earthMoonSpan). Последняя, в свою очередь, тоже имеет двух потомков - Землю (earthSpan) и Луну (moonSpan). Все, как было обсуждено выше.

После загрузки документа запускается программа init(), как обычно.

function init() {
  var NN = (navigator.appName == "Netscape");
  speed = 20;
  moon = (NN) ?
    document.layers["allSpan"].document.layers["earthMoonSpan"].document.layers["moonSpan"] :
    document.all["moonSpan"].style;
  earth = (NN) ?
    document.layers["allSpan"].document.layers["earthMoonSpan"].document.layers["earthSpan"] :
    document.all["earthSpan"].style;
  earthMoon = (NN) ?
    document.layers["allSpan"].document.layers["earthMoonSpan"] :
    document.all["earthMoonSpan"].style;
  sun = (NN) ?
    document.layers["allSpan"] :
    document.all["allSpan"].style;
  initObject(earthMoon,125,1.5,20,1,1,1);
  initObject(moon,16,4,0,-1,1,2);
  initObject(sun,75,1,180,1,1,2);
  moveObjects();
}

В ней определяется переменная NN (true, если имеем дело с Netscape), переменная speed - значение задержки анимации и четыре переменные - объекты содержащие свойства left и top для элементов: sun - система в целом, moon - Луна, earth - Земля и earthMoon - система Земля-Луна. Вообще-то, если бы мы только вращали тела, то объект Земля, нам не был бы нужен - она ведь неподвижна внутри своего родителя. Однако, мы будем использовать его для того, чтобы обработать "заход Луны за Землю" (видели, она там немножко заходит, то сверху, то снизу).

Далее, для каждого движущегося объекта вызывается функция initObject(). Все, что она делает, это добавляет к объекту целый ряд свойств. Эти свойства - суть параметры орбиты. Если Вы посмотрите на эту функцию и на коротенькую функцию circleMove(), которая, собственно и занимается движением, то Вы легко поймете, что означают все эти параметры. Разумеется, неплохо бы, при этом, помнить уравнение эллипса :-)

function initObject(obj,radius,angleinc,anglestart,
    direction,vertical,horizontal) {
  obj.radius = radius;
  obj.angleinc = angleinc;
  obj.anglestart = anglestart;
  obj.angle = anglestart;
  obj.direction = direction;
  obj.vertical = vertical;
  obj.horizontal = horizontal;
  obj.centerX = parseInt(obj.left) -
    horizontal*radius*Math.cos(anglestart*Math.PI/180);
  obj.centerY = parseInt(obj.top) +
    vertical*radius*Math.sin(anglestart*Math.PI/180);
  obj.move = circleMove;
}
  
function circleMove() {
  with (this) {
    angle += direction*angleinc;
    left = centerX +
        horizontal*radius*Math.cos(angle*Math.PI/180);
    top = centerY -
        vertical*radius*Math.sin(angle*Math.PI/180);
  }		
}

Осталось рассмотреть функцию moveObjects(), которая работает пятьесят раз в секунду. Она вызывает circleMove() для отработки движения объектов и управляет zIndex Земли и Луны.

var sunDelay = true;
function moveObjects() {
  earthMoon.move();
  moon.move();
  sunDelay = !sunDelay;		
  if (sunDelay) sun.move();
  if (parseInt(moon.top) > parseInt(earth.top)) {
    if (moon.zIndex != 1) moon.zIndex = 1;
  } else {		
    if (moon.zIndex != 3) moon.zIndex = 3;
  }
  setTimeout("moveObjects()",speed)
}

Манипуляции с переменной sunDelay служат для того, чтобы Солнце двигалось в два раза реже, чем все остальное, а то оно летает неприлично быстро для светила.

Вот, собственно и весь пример.